#include "StdAfx.h"
#include "ThreadRunner.h"

ThreadRunner::ThreadRunner(Runnable& runnable)
	: mThread(0),
	  mThreadID(0),
	  mCancelled(false),
	  mRunnable(runnable)
{
}

ThreadRunner::~ThreadRunner()
{
	Stop();
}

void ThreadRunner::Start()
{
	mCancelled = false;
	mThread = ::CreateThread(NULL, 0, &ThreadProc, this, 0, &mThreadID);
}

DWORD ThreadRunner::ThreadProcImpl()
{
	class ControllerImpl : public Controller
	{
	public:
		ControllerImpl(ThreadRunner& thread)
			: mThread(thread)
		{}
		virtual bool IsCancelled() const
		{
			return mThread.mCancelled;
		}
	private:
		ThreadRunner& mThread;
	} controller(*this);
	mRunnable.Run(controller);
	return controller.IsCancelled() ? 1 : 0;
}

//static
DWORD WINAPI ThreadRunner::ThreadProc(__in  LPVOID lpParameter)
{
	return reinterpret_cast<ThreadRunner*>(lpParameter)->ThreadProcImpl();
}

void ThreadRunner::Stop()
{
	if (0 != mThread)
	{
		if (::GetCurrentThreadId() == mThreadID)
		{
			//::ExitThread(1);
			return;
		}

		bool needTerminate = true;
		DWORD exitCode = 0;
		if (::GetExitCodeThread(mThread, &exitCode))
		{
			needTerminate = false;
			if (STILL_ACTIVE == exitCode)
			{
				mCancelled = true;
				DWORD result = ::WaitForSingleObject(mThread, INFINITE);
				needTerminate = (WAIT_OBJECT_0 != result);
			}
		}
		if (needTerminate)
		{
			::TerminateThread(mThread, 0);
		}

		::CloseHandle(mThread);
		mThread = 0;
	}
}